const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");

const sharp = require("sharp");
const axios = require("axios");
const archiver = require("archiver");
const { app } = require("electron");

function handleImage(options) {
    const filepath = process.env.toFilePath;
    const filename = `transform_${options.filename}`;
    return new Promise((res, rej) => {
        sharp(options.buffer || options.path)
            .resize(Number(options.width), Number(options.height))
            .toBuffer()
            .then((buffer) => res({ buffer: buffer, filename, filepath }))
            .catch((e) => rej(e));
    });
}

function terser(size, fileList) {
    const bacthList = fileList.map((item) => handleImage({ ...size, ...item }));
    return Promise.allSettled(bacthList);
}

class EventHandle {
    static _instance = null;
    static renderInstance() {
        if (!EventHandle._instance) EventHandle._instance = new EventHandle();
        return EventHandle._instance;
    }

    listener(ipcMain, win) {
        const event = JSON.parse(process.env.events || "{}");
        ipcMain.handle(event.TRANSFORM, this.transform);
        ipcMain.handle(event.EXPLORER, this.explorer);
        ipcMain.handle(event.JUDGE_REMOTE_URL, this.judgeRemoteUrl);
        ipcMain.handle(event.EXPORT_ALL, this.exportAll);
        ipcMain.handle(event.MIN_WINDOW, this.minWindow.bind(this, win));
        ipcMain.handle(event.EXIT_WINDOW, this.exitWindow);
        ipcMain.handle(event.GET_APP_INFO, this.getAppInfo);
    }

    transform(_, args) {
        return terser(args.size, args.fileList);
    }

    async judgeRemoteUrl(_, url) {
        try {
            const filename = Date.now() + ".png";
            const imagePath = path.resolve(
                process.env.urlPath + `//${filename}`
            );
            const writeStream = fs.createWriteStream(imagePath);
            const result = await axios.get(url, { responseType: "stream" });
            result.data.pipe(writeStream);
            return await new Promise((res) => {
                writeStream.on("close", () => {
                    console.log(imagePath);
                    res({
                        buffer: fs.readFileSync(imagePath),
                        filename,
                    });
                });
                writeStream.on("error", (e) => rej(e));
            });
        } catch (e) {
            console.error("===== load image is fail... in:", e);
            return false;
        }
    }

    async exportAll(_, fileList) {
        try {
            const filename = Date.now() + ".zip";
            const outputPath = path.resolve(
                process.env.urlPath + "//" + filename
            );
            const writeStream = fs.createWriteStream(outputPath);
            const archiverZip = archiver("zip", {
                zlib: { level: fileList.length },
            });
            for (let item of fileList) {
                archiverZip.append(Buffer.from(item.buffer.buffer), {
                    name: item.filename,
                });
            }
            archiverZip.pipe(writeStream);
            archiverZip.finalize();

            return await new Promise((res, rej) => {
                writeStream.on("close", () => {
                    const buffer = fs.readFileSync(outputPath);
                    res({ buffer, filename });
                });
                writeStream.on("error", (e) => {
                    rej(e);
                });
            });
        } catch (e) {
            console.error("export all file is fail... in:", e);
            return false;
        }
    }

    explorer(_, filePath) {
        try {
            execSync(`explorer ${filePath}`);
        } catch (e) {
            console.error("explorer error...");
        }
    }

    minWindow(win) {
        win.minimize();
    }

    exitWindow() {
        app.quit();
    }

    getAppInfo() {
        return {
            ...JSON.parse(process.env.electronConfig, "{}"),
            title: process.env.appTitle,
        };
    }
}

module.exports = EventHandle.renderInstance();
